#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <linux/fb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
#include <assert.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace cv;

#define RED  0xF800
#define GREEN  0x07E0
#define BLUE  0x001F

typedef unsigned short color_t; /* 根据实际情况修改，此处为unsigned short是565的屏 */

static struct fb_var_screeninfo __g_vinfo; /* 显示信息 */
static color_t *__gp_frame; /* 虚拟屏幕首地址 */

int framebuffer_init(void) {
	int fd = 0;
	fd = open("/dev/fb1", O_RDWR);
	if (fd == -1) {
		perror("fail to open /dev/fb1\n");
		return -1;
	}

	ioctl(fd, FBIOGET_VSCREENINFO, &__g_vinfo); /* 获取显示信息 */
	printf("bits_per_pixel = %d\n", __g_vinfo.bits_per_pixel); /* 一个像素点对应的位数，如果值为16则为565格式输出，如果值为32则为888格式输出 */
	printf("xres_virtual = %d\n", __g_vinfo.xres_virtual); /* 虚拟x轴像素点数 */
	printf("yres_virtual = %d\n", __g_vinfo.yres_virtual); /* 虚拟y轴像素点数 */
	printf("xres = %d\n", __g_vinfo.xres); /* x轴像素点数 */
	printf("yres = %d\n", __g_vinfo.yres); /* y轴像素点数 */

	__gp_frame = (color_t*) mmap(NULL, /* 映射区的开始地址，为NULL表示由系统决定映射区的起始地址 */
			__g_vinfo.xres_virtual * __g_vinfo.yres_virtual
					* __g_vinfo.bits_per_pixel / 8, /* 映射区大小 */
			PROT_WRITE | PROT_READ, /* 内存保护标志（可读可写） */
			MAP_SHARED, /* 映射对象类型（与其他进程共享） */
			fd, /* 有效的文件描述符 */
			0); /* 被映射内容的偏移量 */
	if (__gp_frame == NULL) {
		perror("fail to mmap\n");
		return -1;
	}
	return 0;
}

void full_screen(color_t color) {
	int i;
	color_t *p = __gp_frame;

	for (i = 0; i < __g_vinfo.xres_virtual * __g_vinfo.yres_virtual; i++) {
		*p++ = color;
	}
}

/**
 * https://www.cnblogs.com/siahekai/p/11000789.html
 * https://www.cnblogs.com/Jack-Lee/p/3652957.html
 */

typedef cv::Point3_<uint8_t> Pixel;

void line() {
	int i;
	int start_x = 0;
	int start_y = 75;
	color_t *p = __gp_frame + start_y * __g_vinfo.xres_virtual + start_x;
	for (i = 0; i < __g_vinfo.xres_virtual; i++) {
		*p++ = RED;
	}
	for (i = 0; i < __g_vinfo.xres_virtual; i++) {
		*p++ = GREEN;
	}
	for (i = 0; i < __g_vinfo.xres_virtual; i++) {
		*p++ = BLUE;
	}
}

void loop4() {
	while (1) {
		full_screen (RED);
		sleep(2);
		full_screen (GREEN);
		sleep(2);
		full_screen (BLUE);
		sleep(2);
		full_screen(RED | GREEN);
		sleep(2);
		full_screen(RED | GREEN | BLUE);
		sleep(2);
		full_screen(0);
		sleep(2);
	}
}

int main() {
	if (framebuffer_init()) {
		return -1;
	}
	loop4();
	Mat img1(100, 100, CV_8UC3, Scalar(10, 10, 255));
	imwrite("out.png", img1);
	return 0;
}

